/*
 * CommitmentAction.java   0.0.1    8 Nov 2009
 * 
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */
package org.mentalsmash.tazio.transactions.management;

import java.util.concurrent.Callable;

import org.mentalsmash.documentation.Concurrency;
import org.mentalsmash.tazio.commons.identifiers.OID;
import org.mentalsmash.tazio.transactions.RollbackException;
import org.mentalsmash.tazio.transactions.TransactionStatus;
import org.mentalsmash.tazio.transactions.TransactionalSystemRuntimeException;
import org.mentalsmash.tazio.transactions.management.wrm.WRMCommitmentTask;
import org.mentalsmash.tazio.transactions.objects.RootSet;
import org.mentalsmash.tazio.transactions.objects.TransactionalObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * The abstract class <tt>CommitmentAction</tt> implements a {@link Callable}
 * action that commits the transaction passed as parameter to the constructor.
 * 
 * @author Andrea Reale
 * @version 0.0.1
 * @see WRMCommitmentTask
 */
@Concurrency(concurrentAccess = false, specification = "completely final status + this class should be accessed "
	+ "only a thread at a time. No concurrency concerns")
public abstract class CommitmentAction implements Callable<TransactionStatus> {

    private final static Logger log = LoggerFactory
	    .getLogger(CommitmentAction.class);
    protected final TazioTransaction toCommit;
    protected final RootSet rs;

    /**
     * Do commit the transaction associated to this <tt>CommitmentAction</tt>.
     * If the commitment is performed without problems a
     * {@link TransactionStatus} instance having value
     * {@link TransactionStatus#COMMITTED} is returned. Otherwise
     * {@link Exception}s are thrown to indicate that the transaction was not
     * committed for any reason
     * 
     * @return {@link TransactionStatus#COMMITTED} if the transaction is
     *         succesfully committed
     * @throws TransactionStateException
     *             if the transaction associated to the
     *             <tt>CommitmentAction</tt> is in a state that is not suitable
     *             for commitment
     * @throws RollbackException
     *             if the transaction was rolled back during the commitment
     *             procedure
     */
    @Override
    public abstract TransactionStatus call() throws Exception;

    /**
     * Create a new <tt>CommitmentAction</tt>
     * 
     * @param toCommit2
     *            the {@link TazioTransactionImpl} instance to commit
     */
    public CommitmentAction(final TazioTransaction toCommit2, final RootSet rs) {
	this.toCommit = toCommit2;
	this.rs = rs;
    }

    /**
     * Applies changes to the root set
     */
    protected final void doApplyChanges() {
	

	for (TransactionalOperation op : this.toCommit.getWriteOperations()) {
	    OID targetId = op.getTargetObject();
	    final TransactionalObject obj = this.rs.getObject(targetId);

	    if (obj == null) {
		log.error("Object having OID {} was not found in the root set",
			targetId);
		throw new TransactionalSystemRuntimeException(
			"Expected object " + targetId
				+ " not found in the root set");

	    }
	    op.commitOperation(this.rs);
	    obj.setVersion(this.toCommit.getSeqNo());
	}

    }

}